package com.marketingexpert.controller.taobaomgnt;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import ognl.ParseException;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import sun.misc.BASE64Encoder;

import com.marketingexpert.config.Configuration;
import com.marketingexpert.config.SystemErrorCode;
import com.marketingexpert.dao.cache.CachableAuthorityDao;
import com.marketingexpert.domain.UserType;
import com.marketingexpert.domain.permission.UserRole;
import com.marketingexpert.exception.MarketingExpertException;
import com.marketingexpert.service.authority.InitAuthorityService;
import com.marketingexpert.service.storemgnt.ArticleUserSubscribe;
import com.marketingexpert.service.storemgnt.StoreService;
import com.marketingexpert.service.storemgnt.StoreServiceFactory;
import com.marketingexpert.service.storemgnt.SubscribeService;
import com.marketingexpert.service.usermgnt.UserService;
import com.marketingexpert.util.Resources;
import com.marketingexpert.util.WebUtils;
import com.taobao.api.ApiException;

/**
 * �Ա��Ļص�controller
 * 
 * @author admin
 * 
 */
public class TaobaoCheckAuthController implements Controller {

	private static Logger logger = Logger.getLogger(TaobaoCheckAuthController.class);

	private static SimpleDateFormat sdf = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");
	
	private static SimpleDateFormat sdf2 = new SimpleDateFormat(
	"yyyy-MM-dd 00:00:00");

	private StoreServiceFactory storeServiceFactory = null;
	
	//全站统一异常页面
	private String exceptionPage;
	
	//登录成功的页面
	private String homePage;
	
	
	private UserService userService;
	private Configuration configuration;
	private InitAuthorityService initAuthorityService;
	private SubscribeService subscribeService;
	private CachableAuthorityDao cachableAuthorityDao;

	private SystemErrorCode systemErrorCode;
	
	//taobao service
	private StoreService taobaoAuth;

	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		this.taobaoAuth = storeServiceFactory.getService(StoreServiceFactory.TAOBAO); //获取service
		
		ModelAndView invalidMAV = this.validityCheck(request, response);
		//当有错时, 定向到错误页面
		if(invalidMAV != null) {
			return invalidMAV;
		}
		
	
		
		this.processor(request, response);
		
		try {
			taobaoUser = (com.taobao.api.domain.User) taobaoAuth.getUser(sessionKey);
			// ȡ�Ա��û�������Id,ת����string
			String userId = String.valueOf(taobaoUser.getUserId());
			String nick = taobaoUser.getNick();
			// �û�������Ϣ
			List<ArticleUserSubscribe> userSubInfo = subscribeService.getSubscribe(nick);

			if (userSubInfo == null || userSubInfo.size() <= 0) {
				request.getSession().setAttribute("errorTip",Resources.getString("TaobaoCheckAuthController.subscribeCodeNull"));
				request.getSession().setAttribute("hrefTip", Resources.getString("TaobaoCheckAuthController.subscribeTip"));
				request.getSession().setAttribute("hrefValue", configuration.getUpdateUrl());
				response.sendRedirect(WebUtils.getBasepath(request) + errorPage);
				return null;
			}

			try {
				// ϵͳ�����û���Ȩ����Ϣ
				Map<String, String> authorityInfo = this.getAuthorityInfo(userSubInfo);

				com.marketingexpert.domain.User myDomainUser = null;
				myDomainUser = userService.queryUserByUId(userId);

				String recentlyLogin = sdf.format(new Date());

				// �û���Ȩ�ɹ���,���ǵ�һ����Ȩ���¼�û���Ϣ
				if (myDomainUser == null) {
					myDomainUser = new com.marketingexpert.domain.User(userId,sessionKey, null, UserType.TAOBAO, "0",recentlyLogin);
					myDomainUser.setEndLine(authorityInfo.get("deadline"));
					userService.insert(myDomainUser);
					UserRole ur = new UserRole(Integer.parseInt(authorityInfo.get("roleId")), myDomainUser.getUserId(),authorityInfo.get("description"));
					cachableAuthorityDao.saveUserRole(ur);
				} else {
					myDomainUser.setAccessToken(sessionKey);
					myDomainUser.setEndLine(authorityInfo.get("deadline"));
					myDomainUser.setRecentlyLogin(recentlyLogin);
					userService.updateUser(myDomainUser);
					UserRole ur = new UserRole(Integer.parseInt(authorityInfo.get("roleId")), myDomainUser.getUserId(),authorityInfo.get("description"));
					cachableAuthorityDao.updateUserRole(ur);
				}

				request.getSession().setAttribute("parentUserId", userId);
				request.getSession().setAttribute("userNick", nick);
				request.getSession().setAttribute("taobaoUserType",taobaoUser.getType());
				request.getSession().setAttribute("hasShop",taobaoUser.getHasShop());
				request.getSession().setAttribute("taobaoSessionKey",sessionKey);
				return new ModelAndView(getAuthSuccess());
			} catch (MarketingExpertException e) {
				logger.error(e.getErrMsg(), e);
				if(e.getErrCode().equals("06")){
					request.getSession().setAttribute("errorTip",Resources.getString("TaobaoCheckAuthController.subscribeExpired"));
					request.getSession().setAttribute("hrefTip", Resources.getString("TaobaoCheckAuthController.updatedTip"));
					request.getSession().setAttribute("hrefValue", configuration.getUpdateUrl());
					response.sendRedirect(WebUtils.getBasepath(request) + errorPage);
					return null;
				} else {
					request.getSession().setAttribute("errorTip",Resources.getString("TaobaoCheckAuthController.entrySystemError"));
					request.getSession().setAttribute("hrefTip", Resources.getString("TaobaoCheckAuthController.tryagainTip"));
					request.getSession().setAttribute("hrefValue", configuration.getUpdateUrl());
					response.sendRedirect(WebUtils.getBasepath(request) + errorPage);
					return null;
				}
			}
		} catch (Exception e) {
			logger.error(e);
			String errorCode = "";
			if (e instanceof ApiException) {
				errorCode = ((ApiException) e).getErrCode();
			}
			logger.error(Resources.getString("TaobaoCheckAuthController.errorOccur",new Object[] {errorCode,Resources.getString("TaobaoCheckAuthController.line") + 143 }),e);
			// ��sessionKey��Ч,���û����°�
			if (!errorCode.equals("")) {
				logger.error(Resources.getString("taobaoInvalidSessionKeyMessage"), e);
				request.getSession().setAttribute("failedCause", Resources.getString("taobaoInvalidSessionKeyMessage"));
				return new ModelAndView(getAuthFailed());
			} else {
				request.getSession().setAttribute("failedCause", Resources.getString("taobaoInvalidSessionKeyMessage"));
				return new ModelAndView(getAuthFailed());
			}
		}
	}

	/**
	 * 检查回调参数是否有错误
	 * @param request
	 * @param response
	 * @return
	 */
	private ModelAndView validityCheck(HttpServletRequest request,
			HttpServletResponse response){
		
		String sessionKey = request.getParameter("top_session"); //获取各认证参数
		String top_parameters = request.getParameter("top_parameters");
		String top_sign = request.getParameter("top_sign");
		String top_appkey = request.getParameter("top_appkey");
		String parameter = top_appkey + top_parameters + sessionKey;
		if (sessionKey == null || top_parameters == null || top_sign == null || top_appkey == null) {
			request.getSession().setAttribute("failedCause", Resources.getString("TaobaoCheckAuthController.paramsNotFull"));
			return new ModelAndView(exceptionPage);
		}
		//
		if (!verifyTopResponse(top_parameters, sessionKey, top_sign,configuration.getTaobaoAppKey(), configuration.getTabbaoAppSecret())) {
			request.getSession().setAttribute("failedCause",Resources.getString("TaobaoCheckAuthController.signFailed"));
			return new ModelAndView(exceptionPage);
		}
		//
		if (!validateSign(top_sign, parameter, configuration.getTabbaoAppSecret())) {
			request.getSession().setAttribute("failedCause",Resources.getString("TaobaoCheckAuthController.signFailed"));
			return new ModelAndView(exceptionPage);
		}
		//
		Map<String, String> _top_ParamMap = convertBase64StringtoMap(top_parameters);
		String timeStamp = _top_ParamMap.get("ts");
		Date _tbServerTime = taobaoAuth.getTBServerTime();
		if (!verifyTimstamp(timeStamp, _tbServerTime)) {
			request.getSession().setAttribute("failedCause",Resources.getString("TaobaoCheckAuthController.timestampError"));
			return new ModelAndView(exceptionPage);
		}		
		return null;		
	}

	/**
	 * 获取登录的淘宝用户的信息, 并存储到db
	 * @param sessionKey
	 */
	public void processor(HttpServletRequest request, HttpServletResponse response) {
		String sessionKey = request.getParameter("top_session");
		logger.warn(Resources.getString("TaobaoCheckAuthController.GetSessionKeySuccess")+ sessionKey);
		com.taobao.api.domain.User taobaoUser = (com.taobao.api.domain.User) taobaoAuth.getUser(sessionKey);
		String userId = String.valueOf(taobaoUser.getUserId());
		String nick = taobaoUser.getNick();
		
	}
	
	/**
	 * 检查用户是否存在订阅信息
	 */
	private boolean checkSubscribeInfoIsValid(String nick) {
		List<ArticleUserSubscribe> userSubInfo = subscribeService.getSubscribe(nick);
		//没有获取到订阅信息
		if (userSubInfo == null || userSubInfo.size() <= 0) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 获取用户的订阅类型
	 * 
	 * @param itemCode
	 * @return
	 */
	public Map<String, String> getAuthorityInfo(
			List<ArticleUserSubscribe> userSubInfo) {
		try {
			Map<String, String> _map = new HashMap<String, String>();
			String roleId = null;
			String deadline = null;
			String description = null;

			boolean isPayed = false;

			boolean canUser = false;
			
			for (ArticleUserSubscribe aus : userSubInfo) {
				
				if (aus.getItem_code().equals(configuration.getAppItemCode_payed())) {
					roleId = configuration.getVip_RoleId();
					deadline = aus.getDeadline();
					if (WebUtils.compareDate2(sdf.parse(deadline), sdf2.parse(sdf2.format(new Date())))) {
						isPayed = true;
						canUser = true;
					}
					description = Resources.getString("VIP");
					break;
				}
			}

			if (!isPayed) {
				for (ArticleUserSubscribe aus : userSubInfo) {
					if (aus.getItem_code().equals(configuration.getAppItemCode_free())) {
						canUser = true;
						roleId = configuration.getTryer_RoleId();
						deadline = aus.getDeadline();
						if (!WebUtils.compareDate2(sdf.parse(deadline),sdf2.parse(sdf2.format(new Date())))) {
							throw new MarketingExpertException("06",Resources.getString("TaobaoCheckAuthController.subscribeExpired"));
						}
						description = Resources.getString("TRY");
						break;
					}
				}
			}
			
			if(!canUser) {
				throw new MarketingExpertException("06",Resources.getString("TaobaoCheckAuthController.subscribeExpired"));
			}
				
			_map.put("roleId", roleId);
			_map.put("deadline", deadline);
			_map.put("description", description);
			return _map;
		} catch (MarketingExpertException e) {
			throw e;
		} catch (java.text.ParseException e) {
			logger.error(e.getMessage(), e);
			throw new MarketingExpertException(e);
		}
	}

	/**
	 * 验证时间戳是否在应用允许的误差范围
	 * @param ts
	 * @param tbServerTime
	 * @return
	 */
	public static boolean verifyTimstamp(String ts, Date tbServerTime) {
		if (tbServerTime == null) {
			return false;
		}
		long _ts = Long.parseLong(ts);
		long _serverTime = tbServerTime.getTime();

		if ((_serverTime - _ts) / 60 <= 30) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 验证用户是否已登录
	 * 
	 * @param _top_ParamMap
	 * @return
	 */
	public static boolean verifyUserLogin(Map<String, String> _top_ParamMap) {
		if (_top_ParamMap.containsKey("visitor_id")
				&& _top_ParamMap.containsKey("visitor_nick")) {
			return true;
		} else {
			return false;
		}
	}

	/**
     * 验证TOP回调地址的签名是否合法。要求所有参数均为已URL反编码的。
     * @param topParams TOP私有参数（未经BASE64解密）
     * @param topSession TOP私有会话码
     * @param topSign TOP回调签名
     * @param appKey 应用公钥
     * @param appSecret 应用密钥
     * @param appSecret 应用密钥
     * @return 验证成功返回true，否则返回false
     * @throws NoSuchAlgorithmException
     * @throws IOException
     */
	public static boolean verifyTopResponse(String topParams,
			String topSession, String topSign, String appKey, String appSecret) {
		try {
			StringBuilder result = new StringBuilder();
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			result.append(appKey).append(topParams).append(topSession).append(
					appSecret);
			byte[] bytes = md5.digest(result.toString().getBytes("UTF-8"));
			BASE64Encoder encoder = new BASE64Encoder();
			return encoder.encode(bytes).equals(topSign);
		} catch(NoSuchAlgorithmException e) {
			throw new MarketingExpertException(e);
		} catch(IOException e) {
			throw new MarketingExpertException(e);
		}
	}

	/**
     * 把经过BASE64编码的字符串转换为Map对象
     * @param str
     * @return
     * @throws Exception
     */
	private static Map<String, String> convertBase64StringtoMap(String str) {
		if (str == null)
			return null;
		String keyvalues = null;
		try {
			keyvalues = new String(Base64.decodeBase64(URLDecoder.decode(str,
					"utf-8").getBytes("utf-8")));
		} catch (UnsupportedEncodingException e) {
			logger.error(e.getMessage(), e);
		}
		String[] keyvalueArray = keyvalues.split("\\&");
		Map<String, String> map = new HashMap<String, String>();
		for (String keyvalue : keyvalueArray) {
			String[] s = StringUtils.split(keyvalue, "=");
			if (s == null || s.length != 2)
				return null;
			map.put(s[0], s[1]);
		}
		return map;
	}

	/**
	 * 解析top_parameters
	 * @param top_parameters
	 * @return
	 */
	public String ParametersName(String top_parameters) {
		String nick = null;
		Map<String, String> map = convertBase64StringtoMap(top_parameters);
		Iterator keyValuePairs = map.entrySet().iterator();
		for (int i = 0; i < map.size(); i++) {
			Map.Entry entry = (Map.Entry) keyValuePairs.next();
			Object key = entry.getKey();
			Object value = entry.getValue();
			if (key.equals("visitor_nick")) {
				nick = (String) value;
			}
		}
		return nick;
	}

	 /**
     * 签名运算
     * @param parameter
     * @param secret
     * @return
     * @throws EncryptException
     *
     */
	public static String sign(String parameter, String secret)
			throws MarketingExpertException {
		 // 对参数+密钥做MD5运算
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			logger.error(e.getMessage(), e);
			throw new MarketingExpertException(e);
		}
		byte[] digest = md.digest((parameter + secret).getBytes());

		// 对运算结果做BASE64运算并加密
		BASE64Encoder encode = new BASE64Encoder();
		return encode.encode(digest);
	}

	 /**
     * 验证签名
     * @param sign
     * @param parameter
     * @param secret
     * @return
     * @throws EncryptException
     */
	public static boolean validateSign(String sign, String parameter,
			String secret) throws MarketingExpertException {
		return sign != null && parameter != null && secret != null
				&& sign.equals(sign(parameter, secret));

	}

	public StoreServiceFactory getStoreServiceFactory() {
		return storeServiceFactory;
	}

	public void setStoreServiceFactory(StoreServiceFactory storeServiceFactory) {
		this.storeServiceFactory = storeServiceFactory;
	}

	public String getAuthFailed() {
		return exceptionPage;
	}

	public void setAuthFailed(String authFailed) {
		this.exceptionPage = authFailed;
	}

	public String getAuthSuccess() {
		return homePage;
	}

	public void setAuthSuccess(String authSuccess) {
		this.homePage = authSuccess;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public Configuration getConfiguration() {
		return configuration;
	}

	public void setConfiguration(Configuration configuration) {
		this.configuration = configuration;
	}

	public InitAuthorityService getInitAuthorityService() {
		return initAuthorityService;
	}

	public void setInitAuthorityService(
			InitAuthorityService initAuthorityService) {
		this.initAuthorityService = initAuthorityService;
	}

	public SubscribeService getSubscribeService() {
		return subscribeService;
	}

	public void setSubscribeService(SubscribeService subscribeService) {
		this.subscribeService = subscribeService;
	}

	public CachableAuthorityDao getCachableAuthorityDao() {
		return cachableAuthorityDao;
	}

	public void setCachableAuthorityDao(
			CachableAuthorityDao cachableAuthorityDao) {
		this.cachableAuthorityDao = cachableAuthorityDao;
	}

	public SystemErrorCode getSystemErrorCode() {
		return systemErrorCode;
	}

	public void setSystemErrorCode(SystemErrorCode systemErrorCode) {
		this.systemErrorCode = systemErrorCode;
	}

}
